package com.pig4cloud.pigx.contract.executer.position.margin_appender;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.pig4cloud.pigx.common.customize.exception.MqNotAckException;
import com.pig4cloud.pigx.common.customize.mysql.utils.MysqlUtil;
import com.pig4cloud.pigx.common.customize.security.utils.SecurityUtil;
import com.pig4cloud.pigx.common.customize.utils.CommonUtil;
import com.pig4cloud.pigx.common.seata.utils.SeataUtils;
import com.pig4cloud.pigx.contract.dto.ContractPositionMarginAppendDTO;
import com.pig4cloud.pigx.contract.entity.ContractPosition;
import com.pig4cloud.pigx.contract.entity.ContractPositionMarginDetail;
import com.pig4cloud.pigx.contract.enums.ContractPositionMarginDetailEnum;
import com.pig4cloud.pigx.contract.executer.position.supporter.PositionCalculator;
import com.pig4cloud.pigx.contract.mapper.ContractPositionMapper;
import com.pig4cloud.pigx.contract.mongo.entity.ContractSymbolMongo;
import com.pig4cloud.pigx.contract.utils.ContractUtils;
import com.pig4cloud.pigx.wallet.dto.WalletContractAccountChangeDTO;
import com.pig4cloud.pigx.wallet.enums.WalletContractAccountDetailEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Collections;

/**
 * 仓位全仓自动追加保证金
 *
 * @since 2022/9/22 17:04
 */
@Slf4j
@Component
@AllArgsConstructor
public class PositionMarginAppender {
    private final ContractPositionMapper contractPositionMapper;

    private final ContractUtils contractUtils;
    private final CommonUtil commonUtil;
    private final MysqlUtil mysqlUtil;
    private final SecurityUtil securityUtil;

    /**
     * 监听 contract.position.margin.append 队列，开始处理全仓自动追加保证金
     *
     * @param dto dto
     * @since 2022/9/16 16:00
     */
    public void append(ContractPositionMarginAppendDTO dto) {
        log.info("{} 开始处理全仓自动追加保证金。msg：{}", this.getClass().getSimpleName(), dto);

        // 开启本地事务
        mysqlUtil.startLocalTx();
        // 开启全局事务
        SeataUtils.startGlobalTx();

        ContractPosition position;
        ContractSymbolMongo symbol;
        try {
            // 查询仓位信息并锁定
            ContractPosition condition = new ContractPosition();
            condition.setId(dto.getPositionId());
            position = contractUtils.getOneCurrentPosition(condition, true);
            ContractUtils.checkCurrentPosition(position, false);

            // 查询币对信息
            symbol = contractUtils.getSymbolById(position.getSymbolId());
            ContractUtils.checkSymbol(symbol);

            // 计算标准保证金 - 当前全仓持仓保证金的差额
            BigDecimal difference = PositionCalculator.getFullStandardMarginDifference(position.getOpenAvgPrice(),
                    position.getNowNum(),
                    position.getMultiple(),
                    position.getMargin());

            int compare = difference.compareTo(BigDecimal.ZERO);
            if (compare != 0) {
                // 修改JVM持仓保证金
                position.setMargin(position.getMargin().add(difference));

                // 尝试修改合约余额，多退少补
                WalletContractAccountChangeDTO marginParam = ContractUtils.getChangeAssetParamByPosition(position,
                        difference.abs(),
                        null,
                        WalletContractAccountDetailEnum.BusinessType.POSITION_MARGIN,
                        compare > 0 ? WalletContractAccountDetailEnum.OperationType.ADD : WalletContractAccountDetailEnum.OperationType.MINUS,
                        false);
                contractUtils.changeAsset(Collections.singletonList(marginParam));
            }

            // 修改仓位信息
            UpdateWrapper<ContractPosition> updatePosition = new UpdateWrapper<>();
            updatePosition.lambda()
                    .set(ContractPosition::getMargin, position.getMargin())
                    .set(ContractPosition::getNeedLiquidate, position.getNeedLiquidate())
                    .set(ContractPosition::getLiquidatePrice, position.getLiquidatePrice())
                    .eq(ContractPosition::getId, position.getId());
            if (contractPositionMapper.update(null, updatePosition) != 1) {
                throw new MqNotAckException("修改仓位信息失败");
            }

            // 提交全局事务
            SeataUtils.commitGlobalTx();
            // 提交本地事务
            mysqlUtil.commitLocalTx();

            // 发送重算强平价消息
            contractUtils.sendPositionCrossCalculate(position.getUserId());
        } catch (Throwable e) {
            // 回滚全局事务
            SeataUtils.rollbackGlobalTx();
            // 回滚本地事务
            mysqlUtil.rollbackLocalTx();

            if (e instanceof MqNotAckException) {
                throw e;
            }
        }
    }

    /**
     * 组装仓位保证金变化明细
     *
     * @param positionId     仓位id
     * @param margin         保证金
     * @param businessType   业务类型
     * @param operationType  操作类型
     * @param liquidatePrice 强平价
     * @return {@link ContractPositionMarginDetail}
     * @since 2022/9/16 16:15
     */
    public ContractPositionMarginDetail getMarginDetail(Long positionId,
                                                        BigDecimal margin,
                                                        ContractPositionMarginDetailEnum.BusinessType businessType,
                                                        ContractPositionMarginDetailEnum.OperationType operationType,
                                                        BigDecimal liquidatePrice) {


        ContractPositionMarginDetail detail = new ContractPositionMarginDetail();
        detail.setPositionId(positionId);
        detail.setMargin(margin);
        detail.setBusinessType(businessType.getValue());
        detail.setOperationType(operationType.getValue());
        detail.setLiquidatePrice(liquidatePrice);
        securityUtil.initCreateAbout(detail);

        return detail;
    }
}
